﻿using Downloader;
using FanaticRock.Core.Download;
using System.ComponentModel;
using System.Net;

namespace FanaticRock.DownloadManage.Helpers
{
    public static class DownloadHelper
    {
        private static IDownloadService _downloaderService;
        public static event EventHandler<FileDownloadCompletedEventArgs> DownloadCompleted;
        public static event EventHandler<FileDownloadProgressEventArgs> DownloadProgress;

        public static event AsyncCompletedEventHandler AsyncCompleted;

        //private static WebClient _webClient = new WebClient();
        internal static HttpClient _httpClient = new HttpClient();

        static DownloadHelper()
        {
            var downloadOpt = new DownloadConfiguration()
            {
                ChunkCount = 8, // file parts to download, the default value is 1
                ParallelDownload = true, // download parts of the file as parallel or not. The default value is false,
                RequestConfiguration = new RequestConfiguration()
                {
                    Referer = "https://www.bilibili.com",
                    UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0"
                }
            };

            _downloaderService = new DownloadService(downloadOpt);

            _downloaderService.DownloadStarted += _downloaderService_DownloadStarted;
            _downloaderService.DownloadProgressChanged += _downloaderService_DownloadProgressChanged;
            _downloaderService.DownloadFileCompleted += _downloaderService_DownloadFileCompleted;

            //_webClient.Headers.Add("referer", "https://www.bilibili.com");
            //_webClient.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0");

            //_webClient.DownloadProgressChanged += _webClient_DownloadProgressChanged;
            //_webClient.DownloadFileCompleted += _webClient_DownloadFileCompleted;

        }


        private static void _downloaderService_DownloadStarted(object? sender, DownloadStartedEventArgs e)
        {

        }

        private static void _downloaderService_DownloadFileCompleted(object? sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            if (e.UserState is DownloadPackage package)
            {
                Console.WriteLine(package.Address);
                DownloadCompleted?.Invoke(sender, new FileDownloadCompletedEventArgs()
                {
                    FilePath = package.FileName,
                    Uri = package.Address
                });
            }
        }

        private static void _downloaderService_DownloadProgressChanged(object? sender, Downloader.DownloadProgressChangedEventArgs e)
        {
            DownloadProgress?.Invoke(sender, new FileDownloadProgressEventArgs()
            {
                Progress = e.ProgressPercentage,
                FilePath = _downloaderService.Package.FileName,
                Uri = _downloaderService.Package.Address
            });
        }


        private static void _webClient_DownloadFileCompleted(object? sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            if (e.UserState is DownloadPackage package)
            {
                //Console.WriteLine(package.Address);
                DownloadCompleted?.Invoke(sender, new FileDownloadCompletedEventArgs()
                {
                    FilePath = package.FileName,
                    Uri = package.Address
                });
            }
        }

        private static void _webClient_DownloadProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e)
        {
            DownloadProgress?.Invoke(sender, new FileDownloadProgressEventArgs()
            {
                Progress = e.ProgressPercentage,
                FilePath = _downloaderService.Package.FileName,
                Uri = _downloaderService.Package.Address
            });
        }

        public static async Task DownloadAsync(string url, string fileName, CancellationToken token)
        {
            await Task.Run(() => { DownloadCore(url, fileName, token); });
        }

        private static async Task DownloadCore(string url, string fileName, CancellationToken token)
        {
            //var dir = Path.GetDirectoryName(fileName);
            //if (Directory.Exists(dir) == false) Directory.CreateDirectory(dir);

            //_webClient.DownloadFileTaskAsync(new Uri(url), fileName, token);

            var request = new HttpRequestMessage(HttpMethod.Get, url);
            request.Headers.Add("referer", "https://www.bilibili.com");
            request.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0");

            var response = await _httpClient.SendAsync(request);
            response.EnsureSuccessStatusCode();
            var contentLength = response.Content.Headers.ContentLength.GetValueOrDefault();

            using var stream = await response.Content.ReadAsStreamAsync();

            var dir = Path.GetDirectoryName(fileName);
            if (Directory.Exists(dir) == false) Directory.CreateDirectory(dir);

            var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write);

            var bufferLength = 1024;
            var buffer = new byte[bufferLength];
            var sumLength = 0l;
            var partCount = (int)Math.Ceiling(1d * contentLength / bufferLength);
            var stopCount = 10;

            var internalCount = (int)Math.Floor(1d * partCount / stopCount);
            var partCounter = 0;
            while (true)
            {
                var currentPartLength = await stream.ReadAsync(buffer, 0, buffer.Length);
                if (currentPartLength <= 0)
                {
                    break;
                }
                sumLength += currentPartLength;

                var progress = (double)sumLength / contentLength;

                DownloadProgress?.Invoke(_httpClient, new FileDownloadProgressEventArgs()
                {
                    FilePath = fileName,
                    Uri = url,
                    Progress = progress,
                });

                // 写入到文件
                fileStream.Write(buffer, 0, currentPartLength);
                if (partCounter % internalCount == 0) await Task.Delay(100);
                partCounter++;
            }

            fileStream.Close();
            fileStream.Dispose();

            var args = new FileDownloadCompletedEventArgs()
            {
                FilePath = fileName,
                Uri = url,
            };
            DownloadCompleted?.Invoke(_httpClient, args);

            await Task.Run(() =>
             {
                 while (args.IsHandled == false)
                 {
                     Thread.Sleep(100);
                 }
             });

            //await _downloaderService.DownloadFileTaskAsync(url, fileName, token);
        }


    }
}
